﻿#region Header
//
//   Project:           SilverShader - Silverlight pixel shader demo application for Coding4Fun.
//
//   Changed by:        $Author$
//   Changed on:        $Date$
//   Changed in:        $Revision$
//   Project:           $URL$
//   Id:                $Id$
//
//
//   Copyright (c) 2010 Rene Schulte
//
//   This program is open source software. Please read the License.txt.
//
#endregion

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Collections.ObjectModel;
using SilverShader.ViewModels;

namespace SilverShader
{
   /// <summary>
   /// The main Page of the application.
   /// </summary>
   public partial class MainPage
   {
      private CaptureSource captureSource;

      [ImportMany(AllowRecomposition = true)]
      public ObservableCollection<IShaderViewModel> Shaders;

      public MainPage()
      {
         InitializeComponent();
      }

      private void Initialize()
      {
         try
         {
            // Compose the parts with MEF
            var container = new CompositionContainer(new AssemblyCatalog(GetType().Assembly));
            container.ComposeParts(this);

            // Fill ComboBox
            CmbShaders.ItemsSource = Shaders.OrderBy(s => s.Name);
            CmbShaders.DisplayMemberPath = "Name";
            CmbShaders.SelectedIndex = 1;

            // Init capture source
            captureSource = new CaptureSource();
            try
            {
               captureSource.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
               captureSource.VideoCaptureDevice.DesiredFormat = new VideoFormat(PixelFormatType.Unknown, 640, 480, 30);
            }
            catch (Exception ex)
            {
               MessageBox.Show("Webcam could not be found. Please make sure a default webcam is set.\r\n" + ex.Message, "No webcam", MessageBoxButton.OK);
               BtnCapture.IsEnabled = false;
            }

            // Load initial image
            var bmpImg = new BitmapImage(new Uri("Images/lenna.jpg", UriKind.Relative));
            SetImage(bmpImg);
         }
         catch (Exception ex)
         {
            MessageBox.Show("Error during init.\r\n" + ex.Message, "Error during init.", MessageBoxButton.OK);
            throw;
         }
      }

      private void SetImage(BitmapSource bmpSource)
      {
         // Stop webcam capturing if it's running
         StopCapture();

         // Fill the Viewport rectangle with an Image
         var imgBrush = new ImageBrush();
         imgBrush.ImageSource = bmpSource;
         imgBrush.Stretch = Stretch.Uniform;
         Viewport.Fill = imgBrush;
      }

      private void OpenImage()
      {
         // OpenFileDialog.ShowDialog() can only be called from user-initiated code 
         // like an event handler, otherwise a SecurityException is thrown.
         var openFileDialog = new OpenFileDialog();
         if (openFileDialog.ShowDialog().Value)
         {
            // Open the stream and load the image
            using (var stream = openFileDialog.File.OpenRead())
            {
               var bmpImg = new BitmapImage();
               bmpImg.SetSource(stream);
               SetImage(bmpImg);
               UpdateShader(new Point(bmpImg.PixelWidth, bmpImg.PixelHeight));
            }
         }
      }

      private void StartStopCapture()
      {
         try
         {
            // Start capturing
            if (captureSource.State != CaptureState.Started)
            {
               // Create video brush and fill the rectangle with it
               var vidBrush = new VideoBrush();
               vidBrush.Stretch = Stretch.Uniform;
               vidBrush.SetSource(captureSource);
               Viewport.Fill = vidBrush;

               // Ask user for permission
               if (CaptureDeviceConfiguration.RequestDeviceAccess())
               {
                  captureSource.Start();
                  UpdateShader(new Point(captureSource.VideoCaptureDevice.DesiredFormat.PixelWidth, captureSource.VideoCaptureDevice.DesiredFormat.PixelHeight));
               }
            }
            else
            {
               StopCapture();
            }
         }
         catch (Exception ex)
         {
            MessageBox.Show(ex.Message, "Error using webcam", MessageBoxButton.OK);
            throw;
         }
      }

      public void UpdateShader(Point inputSize)
      {
         if (CmbShaders.SelectedIndex < Shaders.Count)
         {
            var shaderView = Shaders[CmbShaders.SelectedIndex];
            shaderView.InputSize = inputSize;
         }
      }

      private void StopCapture()
      {
         if (captureSource != null)
         {
            captureSource.Stop();
         }
      }



      private void UserControl_Loaded(object sender, RoutedEventArgs e)
      {
         Initialize();
      }

      private void BtnCapture_Click(object sender, RoutedEventArgs e)
      {
         StartStopCapture();
      }

      private void BtnOpenPic_Click(object sender, RoutedEventArgs e)
      {
         OpenImage();
      }

      private void CmbShaders_SelectionChanged(object sender, SelectionChangedEventArgs e)
      {
         if (ShaderParameters == null || Viewport == null)
         {
            return;
         }

         // Clear all
         Viewport.Effect = null;
         ShaderParameters.Children.Clear();

         // Set shader and its views from ComboBox value
         if (CmbShaders != null)
         {
            var selectedShader = CmbShaders.SelectedItem as IShaderViewModel;
            if (selectedShader != null)
            {
               Viewport.Effect = selectedShader.Shader;
               if (selectedShader.View != null)
               {
                  ShaderParameters.Children.Add(selectedShader.View);
               }
            }
         }
      }
   }
}
